package com.evil.common.account.util;

import cn.hutool.core.bean.BeanUtil;
import com.evil.common.account.dto.user.UserBaseRespDTO;
import com.evil.common.account.dto.user.UserEnterpriseBaseDTO;
import com.evil.common.account.enums.PlatformTypeEnum;
import com.evil.common.core.enums.BaseEnum;
import com.evil.common.family.constant.AppConstant;
import com.evil.common.family.entity.TokenInfo;
import com.evil.common.family.enums.RCodeEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.redis.util.RedisUtil;
import com.evil.common.core.util.ServletUtils;
import com.evil.common.family.util.TokenUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.Optional;

/**
 * 登录用户工具栏
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@Component
public class LoginUtil extends TokenUtil {

    public LoginUtil(RedisUtil redisUtil) {
        super(redisUtil);
    }

    /**
     * 获取登录token
     *
     * @return token
     */
    public Optional<String> isExistLoginToken() {
        String key = AppConstant.TOKEN_KEY;
        HttpServletRequest request = ServletUtils.getRequest();
        String userId = (String) request.getAttribute(key);
        if (StringUtils.isBlank(userId)) {
            userId = request.getHeader(key);
        }
        return Optional.ofNullable(userId).filter(StringUtils::isNotBlank);
    }

    /**
     * 获取登录用户ID
     *
     * @return 登录用户ID
     */
    private Optional<Long> isExistLoginUserId() {
        String key = AppConstant.HEADER_USER_ID;
        HttpServletRequest request = ServletUtils.getRequest();
        String userId = (String) request.getAttribute(key);
        if (StringUtils.isBlank(userId)) {
            userId = request.getHeader(key);
        }
        return Optional.ofNullable(userId).filter(StringUtils::isNotBlank).map(Long::valueOf);
    }

    /**
     * 获取登录企业ID
     *
     * @return 登录用户ID
     */
    private Optional<Long> isExistLoginEnterpriseId() {
        String key = AppConstant.HEADER_ENTERPRISE_ID;
        HttpServletRequest request = ServletUtils.getRequest();
        String userId = (String) request.getAttribute(key);
        if (StringUtils.isBlank(userId)) {
            userId = request.getHeader(key);
        }
        return Optional.ofNullable(userId).filter(StringUtils::isNotBlank).map(Long::valueOf);
    }

    /**
     * 获取登录token
     *
     * @return token
     */
    public String getLoginToken() {
        return this.isExistLoginToken().orElseThrow(() -> new BusinessException(RCodeEnum.ERROR_UNAUTHENTICATED));
    }

    /**
     * 获取登录用户ID
     *
     * @return 登录用户ID
     */
    public Long getLoginUserId() {
        return this.isExistLoginUserId().orElseGet(() -> this.getTokenInfo().getUserId());
    }

    /**
     * 获取登录企业ID
     *
     * @return 登录用户ID
     */
    public Long getLoginEnterpriseId() {
        return this.isExistLoginEnterpriseId().orElseGet(() -> this.getTokenInfo().getEnterpriseId());
    }

    /**
     * 获取登录用户基础信息
     *
     * @return UserBaseRespDTO
     */
    public UserBaseRespDTO getLoginUserBase() {
        return BeanUtil.copyProperties(this.getTokenInfo(), UserBaseRespDTO.class);
    }

    /**
     * 获取登录用户与企业信息
     *
     * @return UserEnterpriseDTO
     */
    public UserEnterpriseBaseDTO getLoginUserEnterprise() {
        Optional<Long> userIdOptional = this.isExistLoginUserId();
        if (!userIdOptional.isPresent()) {
            return BeanUtil.copyProperties(this.getTokenInfo(), UserEnterpriseBaseDTO.class);
        }
        return this.isExistLoginEnterpriseId()
                .map(aLong -> new UserEnterpriseBaseDTO(aLong, userIdOptional.get()))
                .orElseGet(() -> BeanUtil.copyProperties(this.getTokenInfo(), UserEnterpriseBaseDTO.class));
    }

    /**
     * 是否登录平台
     *
     * @return boolean
     */
    public boolean isPlatform(Integer platformType) {
        return PlatformTypeEnum.ADMIN_PLATFORM.getId() == platformType;
    }

    /**
     * 是否登录平台
     */
    public void checkPlatform(Integer platformType) {
        if (!this.isPlatform(platformType)) {
            throw new BusinessException(BaseEnum.ACCESS_DENIED);
        }
    }

    /**
     * 检查访问权限（登录企业是否与指定一致，总后台拥有最高访问权限）
     *
     * @param enterpriseId enterpriseId
     */
    public void checkEnterpriseId(Long enterpriseId) {
        TokenInfo tokenInfo = this.getTokenInfo();
        if (PlatformTypeEnum.ENTERPRISE.getId() == tokenInfo.getPlatformType()) {
            if (!tokenInfo.getEnterpriseId().equals(enterpriseId)) {
                // 不一致，拒绝访问
                throw new BusinessException(BaseEnum.ACCESS_DENIED);
            }
        }
    }

    /**
     * 检查当前登录企业是否可以操作 实体（总后台可以操作、同一个企业可以操作）
     *
     * @param entityEId 数据库实体企业ID
     * @param paramEId  参数企业ID
     */
    public void checkEnterpriseId(Long entityEId, Long paramEId) {
        TokenInfo tokenInfo = this.getTokenInfo();
        if (PlatformTypeEnum.ENTERPRISE.getId() == tokenInfo.getPlatformType()) {
            if (!entityEId.equals(paramEId)) {
                // 不一致，拒绝访问
                throw new BusinessException(BaseEnum.ACCESS_DENIED);
            }
        }
    }

    /**
     * 获取参数中企业ID，如果参数没有则获取当前登录企业ID
     *
     * @param userId userId
     * @return userId
     */
    public Long getParamUserId(Long userId) {
        return null == userId ? this.getLoginUserId() : userId;
    }

    /**
     * 获取参数中企业ID，如果参数没有则获取当前登录企业ID
     *
     * @param enterpriseId enterpriseId
     * @return enterpriseId
     */
    public Long getParamEnterpriseId(Long enterpriseId) {
        return null == enterpriseId ? this.getLoginEnterpriseId() : enterpriseId;
    }

    /**
     * 总后台可以查看其他企业
     *
     * @param enterpriseId 企业id
     * @return boolean
     */
    public boolean checkAdminEnterpriseOperate(Long enterpriseId) {
        TokenInfo tokenInfo = this.getTokenInfo();
        return this.isPlatform(tokenInfo.getPlatformType()) && !tokenInfo.getEnterpriseId().equals(enterpriseId);
    }

    /**
     * 获取token
     *
     * @return TokenInfo
     */
    public TokenInfo getTokenInfo() {
        return this.getTokenInfo(this.getLoginToken());
    }


}
